package project.innovation.mooddiagnosis.service.impl;

//import jnr.ffi.annotations.In;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import project.innovation.mooddiagnosis.dao.ChunkMapper;
import project.innovation.mooddiagnosis.entity.file.ChunkInfo;
import project.innovation.mooddiagnosis.service.ChunkService;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
//import java.util.concurrent.*;

//class MyCallable implements Callable<String> {
//    private String chunkFileName;
//
//    public MyCallable(String chunkFileName) {
//        this.chunkFileName = chunkFileName;
//    }
//
//    private static final Logger logger = LoggerFactory.getLogger(MyCallable.class);
//
//    @Override
//    public String call() throws IOException, InterruptedException {
//        String [] splits = chunkFileName.split("\\.");
//        String type = splits[splits.length - 1];
//        String fileName = splits[splits.length - 2];
//        String chunkFileName_changed=fileName + "+changed"+"."+type;
//
//        ProcessBuilder pb_change = new ProcessBuilder("ffmpeg", "-i", chunkFileName , "-c:v", "libx264" ,"-crf", "23", "-preset", "medium", "-c:a", "aac", "-b:a", "192k", chunkFileName_changed);
//        Process process = pb_change.inheritIO().start();
//        int exitCode = process.waitFor();
//
//        if(exitCode != 0){
//            logger.error("file change something wrong");
//        }
//        return chunkFileName_changed;
//    }
//}

@Service
public class ChunkServiceImpl implements ChunkService {
    @Autowired
    private ChunkMapper chunkMapper;
    @Value("${LINUXFilePath}")
    private String linuxFilePath;

//    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);

    private static final Logger logger = LoggerFactory.getLogger(ChunkServiceImpl.class);

    @Override
    public Integer saveChunk(MultipartFile chunk, String md5, Integer index, Long chunkSize, String chunkFileName, String chunkFileName_changed) throws IOException, InterruptedException {
//        System.out.println("resultFileName in ChunkService " + chunkFileName);
        try(BufferedInputStream bis = new BufferedInputStream(chunk.getInputStream())){
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(chunkFileName, true));

            int bytesRead = 0;
            byte[] buffer = new byte[1024];
            while((bytesRead = bis.read(buffer)) != -1){
                bos.write(buffer, 0, bytesRead);
            }

            logger.info("chunk has been wrote to {}", chunkFileName);
        }   catch (IOException e){
            e.printStackTrace();
        }

        ChunkInfo chunkInfo = new ChunkInfo(md5, index);
        return chunkMapper.insertChunk(chunkInfo);
    }

    @Override
    public List<ChunkInfo> selectChunkListByMd5(String md5){
        return chunkMapper.selectChunkListByMd5(md5);
    }

    @Override
    public void deleteChunkByMd5(String md5){
        chunkMapper.deleteChunkByMd5(md5);
    }
    @Override
    public byte[] getChunk(Integer index, Integer chunkSize, String resultFileName, long offset){
        File resultFile = new File(resultFileName);
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(resultFile, "r")){
            randomAccessFile.seek(offset);
            byte[] bytes = new byte[chunkSize];
            randomAccessFile.read(bytes);
            return bytes;
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public Integer mergeChunk(String md5, String resultFilename, Integer index) throws IOException, InterruptedException {
        logger.info("merge {} Chunk. waiting all chunk upload", index);
        while(chunkMapper.selectChunkListByMd5(md5).size() != index){
        }
        logger.info("all chunk uploaded. {}", chunkMapper.selectChunkListByMd5(md5).size());
        
        File resultFile = new File(resultFilename);
        if (!resultFile.getParentFile().exists()) {
            logger.info("parent directory does not exist {}", resultFile.getParentFile());
            // 可以选择性地创建父目录
             resultFile.getParentFile().mkdirs();
        }
        if (resultFile.exists()) {
            logger.info("file already exists {}", resultFile.getAbsolutePath());
        } else {
            logger.info("file not exists {}", resultFile.getAbsolutePath());
        }

        File directory = new File(linuxFilePath);
        File[] files = directory.listFiles(); // 列出目录中的所有文件和文件夹
//        List<Future<String>> list = new ArrayList<>();

//        if(files != null){
//            for (File file : files) {
//                if (file.getAbsolutePath().equals(resultFilename)) continue;
//                if (file.getName().contains(md5)) {
//                    Future<String> thread = executorService.submit(new MyCallable(file.getAbsolutePath()));
//                    list.add(thread);
//                }
//            }
//        }
//
//        List<String> changed_file_name_list = list.stream().map(stringFuture -> {
//            try{
//                return stringFuture.get();
//            } catch (InterruptedException | ExecutionException e) {
//                e.printStackTrace();
//            }
//            return null;
//        }).toList();

        List<String> changed_file_name_list = new ArrayList<>();

        if(files != null){
            for (File file : files) {
                if (file.getAbsolutePath().equals(resultFilename)) continue;
                if (file.getName().contains(md5)) {
//                    Future<String> thread = executorService.submit(new MyCallable(file.getAbsolutePath()));
//                    list.add(thread);
                    changed_file_name_list.add(changeFileType(file.getAbsolutePath()));
                }
            }
        }

        // 遍历文件
        for(String file : changed_file_name_list){
            logger.info("changed file {}", file);
        }

        File tempFile = File.createTempFile("videoList"+resultFilename,".txt");

        try(java.io.PrintWriter pw = new java.io.PrintWriter(tempFile)){
            for(String video:changed_file_name_list){
                pw.println("file '"+video+"'");
            }
        }

        ProcessBuilder pb_merge = new ProcessBuilder("ffmpeg", "-f", "concat", "-safe", "0", "-i", tempFile.getAbsolutePath(), "-c", "copy", resultFilename);
        Process process = pb_merge.inheritIO().start();
        int exitCode = process.waitFor();

        tempFile.delete();

        return exitCode;
    }

    String changeFileType(String chunkFileName) throws IOException, InterruptedException {
        String [] splits = chunkFileName.split("\\.");
        String type = splits[splits.length - 1];
        String fileName = splits[splits.length - 2];
        String chunkFileName_changed=fileName + "+changed"+"."+type;

        ProcessBuilder pb_change = new ProcessBuilder("ffmpeg", "-i", chunkFileName , "-c:v", "libx264" ,"-crf", "23", "-preset", "medium", "-c:a", "aac", "-b:a", "192k", chunkFileName_changed);
        Process process = pb_change.inheritIO().start();
        int exitCode = process.waitFor();

        if(exitCode != 0){
            logger.error("file change something wrong");
        }
        return chunkFileName_changed;
    }
}
